#include "audio_stream_tts.h"
#include <iostream>
#include <stdexcept>
#include <string.h>

#include "conf.h"
#include <cmath>

#include <cstring>


#define TTS_SAMPLE_RATE   44100


// ！！！ 注意不同的模型它合成的音频采样率可能会不同，要注意修改


// 半个椭圆球扬声器的设备名称
// #define SPEAKER_DEVICE_NAME "UACDemoV1.0: USB Audio"

// 使用蓝牙耳机的时候，使用 pulse 或者 default 可以正常播放
// #define SPEAKER_DEVICE_NAME "pulse"
// #define SPEAKER_DEVICE_NAME "default"

// #define SPEAKER_DEVICE_NAME "sysdefault"

#define SPEAKER_DEVICE_NAME "default"

// TtsEngine 类实现

// // 构造函数：初始化 TTS 模型
// TtsEngine::TtsEngine(): tts_(nullptr) {
//     // 初始化 sherpa-onnx 的 TTS 配置
//     SherpaOnnxOfflineTtsConfig config;
//     memset(&config, 0, sizeof(config));

//     config.rule_fsts = "/opt/sherpa-onnx/kokoro-multi-lang-v1_0/date-zh.fst,"
//                        "/opt/sherpa-onnx/kokoro-multi-lang-v1_0/number-zh.fst,"
//                        "/opt/sherpa-onnx/kokoro-multi-lang-v1_0/phone-zh.fst";

//     config.model.kokoro.model = "/opt/sherpa-onnx/kokoro-multi-lang-v1_0/model.onnx";
//     config.model.kokoro.voices = "/opt/sherpa-onnx/kokoro-multi-lang-v1_0/voices.bin";
//     config.model.kokoro.tokens = "/opt/sherpa-onnx/kokoro-multi-lang-v1_0/tokens.txt";
//     config.model.kokoro.data_dir = "/opt/sherpa-onnx/kokoro-multi-lang-v1_0/espeak-ng-data";
//     config.model.kokoro.dict_dir = "/opt/sherpa-onnx/kokoro-multi-lang-v1_0/dict";
//     config.model.kokoro.lexicon =
//         "/opt/sherpa-onnx/kokoro-multi-lang-v1_0/lexicon-us-en.txt,"
//         "/opt/sherpa-onnx/kokoro-multi-lang-v1_0/lexicon-zh.txt";



TtsEngine::TtsEngine(): tts_(nullptr) {
    // TtsEngine::TtsEngine(): tts_(nullptr), audio_processing_ptr(webrtc::AudioProcessing::Create()){

    SherpaOnnxOfflineTtsConfig config;
    memset(&config, 0, sizeof(config));
    
    config.model.vits.dict_dir = "/opt/sherpa-onnx/vits-melo-tts-zh_en/dict";
    config.model.vits.tokens   = "/opt/sherpa-onnx/vits-melo-tts-zh_en/tokens.txt";
    config.model.vits.model    = "/opt/sherpa-onnx/vits-melo-tts-zh_en/model.onnx";
    config.model.vits.lexicon  = "/opt/sherpa-onnx/vits-melo-tts-zh_en/lexicon.txt";

    config.rule_fsts = "/opt/sherpa-onnx/vits-melo-tts-zh_en/date.fst,"
                       "/opt/sherpa-onnx/vits-melo-tts-zh_en/new_heteronym.fst,"
                       "/opt/sherpa-onnx/vits-melo-tts-zh_en/number.fst,"
                       "/opt/sherpa-onnx/vits-melo-tts-zh_en/phone.fst";


    config.model.num_threads = 7;  // 线程数
    config.model.debug = 0;        // 调试模式
    // config.model.provider = "cuda";
    config.model.provider = "cpu";

    // 创建 TTS 模型
    tts_ = SherpaOnnxCreateOfflineTts(&config);



    // ===============================================================================
    // 对 tts 生成的音频进行降噪处理 begin >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // ===============================================================================
    // // 创建 AudioProcessing 实例，使用原始指针
    // audio_processing = webrtc::AudioProcessing::Create();

    // if (!audio_processing) {
    //     std::cerr << "Failed to create AudioProcessing instance!" << std::endl;
    //     return;
    // }

    // // 使用 std::move 将原始指针转移到 std::unique_ptr 中
    // std::unique_ptr<webrtc::AudioProcessing> audio_processing_ptr = std::move(audio_processing);


    // // 获取噪声抑制模块并启用
    // webrtc::NoiseSuppression* noise_suppression = audio_processing_ptr->noise_suppression();
    // if (noise_suppression) {
    //     noise_suppression->Enable(true);
    //     noise_suppression->set_level(webrtc::NoiseSuppression::Level::kHigh);
    //     std::cout << "WebRTC noise suppression enabled!" << std::endl;
    // } else {
    //     std::cerr << "Failed to get NoiseSuppression module!" << std::endl;
    // }


    // 模拟音频数据
    // const int num_samples = 480;  // 每帧 480 个样本
    // int16_t audio_data[num_samples];  // 音频数据（int16_t 类型）
    
    // // 填充音频数据（假设这是从某处获取的音频数据）
    // for (int i = 0; i < num_samples; ++i) {
    //     audio_data[i] = static_cast<int16_t>(rand() % 32768);  // 随机填充数据
    // }

    // 处理音频数据
    // WebRTC 的 `AudioProcessing` 并不直接接受原始音频数据数组，而是通常处理 `AudioFrame` 类型对象，
    // 但我们可以手动管理音频数据并使用 `AudioProcessing::ProcessStream` 来处理音频。




    // // 假设你有 160 个样本，1 个通道，采样率为 16000 Hz
    // size_t samples_per_channel = 160;

    // // 创建输入和输出的浮动音频缓冲区
    // float* input_audio[1];  // 1 个通道
    // float input_buffer[160];  // 每个通道 160 个样本
    // input_audio[0] = input_buffer;  // 假设你已经填充了 input_buffer

    // float* output_audio[1];  // 1 个通道
    // float output_buffer[160];  // 每个通道 160 个样本
    // output_audio[0] = output_buffer;

    // // 使用 StreamConfig 构造函数来创建输入和输出配置
    // bool has_keyboard = false;  // 假设没有键盘通道
    // webrtc::StreamConfig input_config(input_sample_rate_hz, 1, has_keyboard);  // 输入配置：采样率16000，1个通道
    // webrtc::StreamConfig output_config(output_sample_rate_hz, 1, has_keyboard);  // 输出配置：采样率16000，1个通道

    // // 调用 ProcessStream 来处理音频数据
    // int result = audio_processing_ptr->ProcessStream(input_audio, samples_per_channel, TTS_SAMPLE_RATE, webrtc::AudioProcessing::ChannelLayout::kMono,
    //                                                  TTS_SAMPLE_RATE, webrtc::AudioProcessing::ChannelLayout::kMono, output_audio);
    // if (result != 0) {
    //     std::cerr << "Error processing audio stream!" << std::endl;
    //     return -1;
    // }

    // std::cout << "Audio processing completed!" << std::endl;
    // ===============================================================================
    // 对 tts 生成的音频进行降噪处理 begin >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // ===============================================================================
}

// 析构函数：释放 TTS 模型资源
TtsEngine::~TtsEngine() {
    if (tts_) {
        SherpaOnnxDestroyOfflineTts(tts_);
    }
}

// 生成音频数据：将文本转换为音频数据
// 生成的音頻是：單通道， 22050 採樣率
std::vector<float> TtsEngine::generate(const std::string &text, int sid, float speed) {
    if (tts_ == NULL) {
        err_log("tts init error, 'tts_' was NULL.");
        return std::vector<float>(); 
    }

    // 调用 sherpa-onnx 的 API 生成音频数据
    const SherpaOnnxGeneratedAudio *audio = SherpaOnnxOfflineTtsGenerate(tts_, text.c_str(), sid, speed);

    if (!audio) {
        // throw std::runtime_error("TTS generation failed.");
        err_log("TTS generation failed, audio = nullptr");
    }

    // 验证 audio->samples 和 audio->n 的值
    // std::cout << "Audio samples address: " << audio->samples << std::endl;
    // std::cout << "Audio sample count: " << audio->n << std::endl;

    // 将生成的音频数据复制到 std::vector<float> 中
    std::vector<float> samples(audio->samples, audio->samples + audio->n);

    // sys_log("copied done!");

    // 释放生成的音频数据
    SherpaOnnxDestroyOfflineTtsGeneratedAudio(audio);

    return samples;

    // =======================================================================================
    // 对 TTS 生成的音频进行降噪处理
    // =======================================================================================
    // 假设 TTS 生成的音频只有 1 个通道
    // size_t samples_per_channel = samples.size();  // 音频数据的样本数

    // // 创建输入和输出的浮动音频缓冲区
    // float* input_audio[1];  // 1 个通道
    // float* input_buffer = new float[samples_per_channel];  // 堆上的缓冲区
    // std::memcpy(input_buffer, samples.data(), samples_per_channel * sizeof(float));  // 将音频数据复制到缓冲区
    // input_audio[0] = input_buffer;

    // float* output_audio[1];  // 1 个通道
    // float* output_buffer = new float[samples_per_channel];  // 堆上的缓冲区
    // output_audio[0] = output_buffer;

    // webrtc::StreamConfig input_config(TTS_SAMPLE_RATE, 1, false);  // 输入配置：采样率为 TTS_SAMPLE_RATE，1 个通道
    // webrtc::StreamConfig output_config(TTS_SAMPLE_RATE, 1, false);  // 输出配置：采样率为 TTS_SAMPLE_RATE，1 个通道

    // // 调用 ProcessStream 来处理音频数据
    // int result = audio_processing_ptr->ProcessStream(input_audio, samples_per_channel, TTS_SAMPLE_RATE, 
    //                                                  webrtc::AudioProcessing::ChannelLayout::kMono,
    //                                                  TTS_SAMPLE_RATE, webrtc::AudioProcessing::ChannelLayout::kMono, output_audio);

    // if (result != 0) {
    //     err_log("Error processing audio stream!");
    //     return std::vector<float>();
    // }

    // // 将处理后的音频数据复制到 std::vector<float> 中并返回
    // std::vector<float> processed_samples(output_buffer, output_buffer + samples_per_channel);
    
    // delete[] input_buffer;
    // delete[] output_buffer;

    // return processed_samples;
}






// AudioPlayer 类实现

void AudioPlayer::printAllDevices(void)
{
    // get num of audio devices
    int numDevices = Pa_GetDeviceCount();
    if (numDevices < 0) {
        err_log("Error getting device count: %d", numDevices);
    }

    for (int i = 0; i < numDevices; ++i) {
        const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo(i);
        if (deviceInfo->maxOutputChannels > 0) {
            // sys_log("device[%d], in[%d]: %s", i, deviceInfo->maxOutputChannels, deviceInfo->name);
        }
    }
}

// 构造函数：初始化音频播放器
AudioPlayer::AudioPlayer(int sample_rate, int frames_per_buffer)
    : sample_rate_(sample_rate), frames_per_buffer_(frames_per_buffer), stream_(nullptr), is_playing_(false) {

    int deviceIndex = -1;
    int maxDevchannel = 1;

    // get num of audio devices
    int numDevices = Pa_GetDeviceCount();
    if (numDevices < 0) {
        err_log("Error getting device count: %d", numDevices);
    }

    for (int i = 0; i < numDevices; ++i) {
        const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo(i);
        if (deviceInfo->maxOutputChannels > 0) {
            sys_log("device[%d], in[%d]: %s", i, deviceInfo->maxOutputChannels, deviceInfo->name);
        }

        // 选择对应名称的设备
        std::string_view str(deviceInfo->name);
        if (str.starts_with( SPEAKER_DEVICE_NAME )) {
            deviceIndex = i;
            maxDevchannel = deviceInfo->maxOutputChannels;
        }
    }

    if (deviceIndex == -1) {
        err_log("can not find the device with name(%s)", SPEAKER_DEVICE_NAME);
        return;
    }

    sys_log("audio player select device: [%d]_%s, max channel num: %d", deviceIndex, SPEAKER_DEVICE_NAME, maxDevchannel);

    // 获取所选设备信息
    const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo(deviceIndex);
    if (!deviceInfo) {
        sys_log("Can not get the device info: Invalid device index: %d", deviceIndex);
        return;
    }

    maxDevchannel = 1;

    // 设置 PaStreamParameters 以指定设备
    PaStreamParameters outputParameters;
    outputParameters.device = deviceIndex; // 选择设备
    outputParameters.channelCount = maxDevchannel;  // sherpa 生成的音頻是單通道的
    outputParameters.sampleFormat = paFloat32;  // 音频数据格式为浮点数
    outputParameters.suggestedLatency = Pa_GetDeviceInfo(deviceIndex)->defaultLowOutputLatency; // 设置低延迟
    outputParameters.hostApiSpecificStreamInfo = nullptr; // 不使用主机 API 特定的信息

    // ! 使用設備支持的 sample rate
    sample_rate_ = deviceInfo->defaultSampleRate;
    // sample_rate_ = 22050;
    sys_log("use device support sample rate: %d", sample_rate_);

    // use the default audio out stream
    // 打开默认音频输出流
    // PaError err = Pa_OpenDefaultStream(&stream_, 0, 1, paFloat32, sample_rate_, frames_per_buffer_, paCallback, this);
    // if (err != paNoError) {
    //     throw std::runtime_error("PortAudio stream open failed: " + std::string(Pa_GetErrorText(err)));
    // }

    // open 'deviceIndex' device
    PaError err = Pa_OpenStream(&stream_, nullptr, &outputParameters, sample_rate_, frames_per_buffer_,
        paClipOff, paCallback, this);  // 使用选择的设备
    if (err != paNoError) {
        err_log("PortAudio stream open failed: %s", Pa_GetErrorText(err));
        return;
    }

    sys_log("Audio player initialized with device: %s", deviceInfo->name);

    sys_log("audio player select device: [%d]_%s, max channel num: %d", deviceIndex, SPEAKER_DEVICE_NAME, maxDevchannel);
}


// 析构函数：释放音频播放器资源
AudioPlayer::~AudioPlayer() {
    stop();
    if (stream_) {
        Pa_CloseStream(stream_);
    }
}


// 启动音频播放器
void AudioPlayer::start() {
    if (!is_playing_) {
        is_playing_ = true;
        PaError err = Pa_StartStream(stream_);
        if (err != paNoError) {
            throw std::runtime_error("PortAudio stream start failed: " + std::string(Pa_GetErrorText(err)));
        }
    }
}

// 停止音频播放器
void AudioPlayer::stop() {
    if (is_playing_) {
        is_playing_ = false;
        // Pa_StopStream(stream_);   // 会等待缓冲区中的数据播放完毕
        if (stream_)
            Pa_AbortStream(stream_);  // 直接终止流，不等待
    }
}

// 将音频数据推送到播放缓冲区
void AudioPlayer::pushAudio(const std::vector<float> &samples) {

    if (is_mute) {  // 如果是 audioPlayer 被静音的话，那就放弃这次将 samples 写入 buffer
        return;
    }

    // 在这里修改原始合成音频的采样率
    float inputRate = 44100;  // vits
    // float inputRate = 24000;  // 

    // 因为sherpa 合成的音频是单声道的，所以这里设置为1
    int channels = 1;

    // 先进行采样率的转换
    int error;
    src_state = src_new(SRC_SINC_BEST_QUALITY, 1, &error);
    if (error) {
        err_log("libsamplerate0 init error: %d", error);
        return;
    }

    // 计算输入和输出的缓冲区大小
    size_t inputSize = samples.size();
    size_t outputSize = static_cast<size_t>(std::ceil(inputSize * static_cast<double>(sample_rate_) / inputRate));

    // 在堆上分配内存
    std::unique_ptr<float[]> inputSamples = std::make_unique<float[]>(inputSize);
    std::unique_ptr<float[]> outputSamples = std::make_unique<float[]>(outputSize);

    // 复制输入数据
    std::copy(samples.begin(), samples.end(), inputSamples.get());

    // 设置 SRC_DATA 结构
    SRC_DATA src_data;
    src_data.data_in = inputSamples.get();
    src_data.data_out = outputSamples.get();
    src_data.input_frames = inputSize / 1;
    src_data.output_frames = outputSize / 1;
    src_data.src_ratio = static_cast<double>(sample_rate_) / inputRate;

    // 执行采样率转换
    int error_ = src_process(src_state, &src_data);
    if (error_) {
        throw std::runtime_error("Sample rate conversion failed: " + std::string(src_strerror(error_)));
    }

    // 删除 libsamplerate 资源
    if (src_state) {
        src_delete(src_state);
    }

    // 将转换后的数据推送到播放缓冲区
    std::lock_guard<std::mutex> lock(audio_mutex_);

    for (size_t i = 0; i < src_data.output_frames_gen * channels; ++i) {
        audio_buffer_.push(outputSamples[i]);
    }
}


// 检查音频是否正在播放
bool AudioPlayer::isPlaying() const {
    return is_playing_;
}

// PortAudio 回调函数：用于填充音频数据
int AudioPlayer::paCallback(const void *inputBuffer, void *outputBuffer,
                            unsigned long framesPerBuffer,
                            const PaStreamCallbackTimeInfo *timeInfo,
                            const PaStreamCallbackFlags statusFlags,
                            void *userData) {
    AudioPlayer *player = static_cast<AudioPlayer *>(userData);
    if (player == nullptr) {
        return paContinue;
    }

    return player->audioCallback(outputBuffer, framesPerBuffer);
}

// 音频回调函数：从缓冲区中读取数据并填充到输出缓冲区
int AudioPlayer::audioCallback(void *outputBuffer, unsigned long framesPerBuffer) {

    float *out = static_cast<float *>(outputBuffer);

    lastAudioBufferEmpty = curAudioBufferEmpty;

    std::unique_lock<std::mutex> lock(audio_mutex_);

    curAudioBufferEmpty = audio_buffer_.empty() ? true : false;

    // memset(out, 0, framesPerBuffer * maxDevchannel * sizeof(float));

    /* 将 audio_buffer_ 中的内容复制到 PortAudio 的缓冲区中进行播放 */
    if (maxDevchannel == 1) {
        // 单声道数据
        for (unsigned long i = 0; i < framesPerBuffer; i++) {
            if (!audio_buffer_.empty()) {
                *out++ = audio_buffer_.front();
                audio_buffer_.pop();
            }
        }// end of 'for'
    } else if (maxDevchannel == 2) {

        memset(out, 0, framesPerBuffer * maxDevchannel * sizeof(float));

        // 双声道数据
        for (unsigned long i = 0; i < framesPerBuffer; i++) {

            float sample = 0.0f; // 默认静音
            if (!audio_buffer_.empty()) {
                sample = audio_buffer_.front();
                audio_buffer_.pop();
                // *out++ = sample;  // 左声道
                // *out++ = sample;  // 右声道
            }
    
            out[2 * i] = sample;
            out[2 * i + 1] = sample;
            
        }// end of 'for'

    }// end of 'if'
    else {
        err_log("invaild maxDevchannel value: %d", maxDevchannel);
    }

    lock.unlock();

    if (!lastAudioBufferEmpty && 
        curAudioBufferEmpty && 
        buffer_transitionToEmpty_callback) {
            buffer_transitionToEmpty_callback();
    }

    return paContinue;  // 继续播放
}
